Convenience function that turns an integral into the corresponding Checked instance by using template argument deduction. The hook type may be specified (by default Abort).
Defines binary operations with overflow checking for any two integral types. The result type obeys the language rules (even when they may be counterintuitive), and overflow is set if an overflow occurs (including inadvertent change of signedness, e.g. -1 is converted to uint). Conceptually the behavior is:
Force all integral errors to fail by printing an error message to stderr and then abort the program. Abort is the default second argument for Checked.
Checked integral type wraps an integral T and customizes its behavior with the help of a Hook type. The type wrapped must be one of the predefined integrals (unqualified), or another instance of Checked.
Hook that provides arithmetically correct comparisons for equality and ordering. Comparing an object of type Checked!(X, ProperCompare) against another integral (for equality or ordering) ensures that no surprising conversions from signed to unsigned integral occur before the comparison. Using Checked!(X, ProperCompare) on either side of a comparison for equality against a floating-point number makes sure the integral can be properly converted to the floating point type, thus making sure equality is transitive.
Hook that implements saturation, i.e. any arithmetic operation that would overflow leaves the result at its extreme value (min or max depending on the direction of the overflow).
Force all integral errors to fail by throwing an exception of type Throw.CheckFailure. The message coming with the error is similar to the one printed by Warn.
Hook that prints to stderr a trace of all integral errors, without affecting default behavior.
Hook that reserves a special value as a "Not a Number" representative. For signed integrals, the reserved value is T.min. For signed integrals, the reserved value is T.max.
1 int[] concatAndAdd(int[] a, int[] b, int offset) 2 { 3 // Aborts on overflow on size computation 4 auto r = new int[(checked(a.length) + b.length).get]; 5 // Aborts on overflow on element computation 6 foreach (i; 0 .. a.length) 7 r[i] = (a[i] + checked(offset)).get; 8 foreach (i; 0 .. b.length) 9 r[i + a.length] = (b[i] + checked(offset)).get; 10 return r; 11 } 12 assert(concatAndAdd([1, 2, 3], [4, 5], -1) == [0, 1, 2, 3, 4]);
This module defines facilities for efficient checking of integral operations against overflow, casting with loss of precision, unexpected change of sign, etc. The checking (and possibly correction) can be done at operation level, for example opChecked!"+"(x, y, overflow) adds two integrals x and y and sets overflow to true if an overflow occurred. The flag overflow (a bool passed by reference) is not touched if the operation succeeded, so the same flag can be reused for a sequence of operations and tested at the end.
Issuing individual checked operations is flexible and efficient but often tedious. The Checked facility offers encapsulated integral wrappers that do all checking internally and have configurable behavior upon erroneous results. For example, Checked!int is a type that behaves like int but aborts execution immediately whenever involved in an operation that produces the arithmetically wrong result. The accompanying convenience function checked uses type deduction to convert a value x of integral type T to Checked!T by means of checked(x). For example, checked(1_000_000) * 10_000 aborts execution because the operation overflows. Also, checked(-1) > uint(0) aborts execution (even though the built-in comparison int(-1) > uint(0) is surprisingly true due to language's conversion rules modeled after C). Thus, Checked!int is a virtually drop-in replacement for int useable in debug builds, to be replaced by int in release mode if efficiency demands it.
Checked has customizable behavior with the help of a second type parameter, Hook. Depending on what methods Hook defines, core operations on the underlying integral may be verified for overflow or completely redefined. If Hook defines no method at all and carries no state, there is no change in behavior, i.e. Checked!(int, void) is a wrapper around int that adds no customization at all.
This module provides a few predefined hooks (below) that add useful behavior to Checked:
These policies may be used alone, e.g. Checked!(uint, WithNaN) defines a uint-like type that reaches a stable NaN state for all erroneous operations. They may also be "stacked" on top of each other, owing to the property that a checked integral emulates an actual integral, which means another checked integral can be built on top of it. Some combinations of interest include:
The hook's members are looked up statically in a Design by Introspection manner and are all optional. The table below illustrates the members that a hook type may define and their influence over the behavior of the Checked type using it. In the table, hook is an alias for Hook if the type Hook does not introduce any state, or an object of type Hook otherwise.